home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / program / fpk65_66.zip / SOURCE / RTL / DOS / DOS.PP < prev    next >
Text File  |  1997-02-03  |  22KB  |  847 lines

  1. {****************************************************************************
  2.  
  3.                           FPKPascal Runtime-Library
  4.                           Copyright (c) 1994,97 by
  5.                     Florian Klaempfl and Michael Spiegel
  6.  
  7.  ****************************************************************************}
  8.  
  9. {
  10.   History:
  11.   2.7.1994: Version 0.2
  12.             Datenstrukturen sind deklariert sowie
  13.             50 % der Unterprogramme sind implementiert
  14.   12.8.1994: exec implemented
  15.   14.8.1994: findfirst and findnext implemented
  16.   24.8.1994: Version 0.3
  17.   28.2.1995: Version 0.31
  18.              some parameter lists with const optimized
  19.    3.7.1996: bug in fsplit removed (dir and ext were not intializised)
  20.    7.7.1996: packtime and unpacktime implemented
  21.   20.9.1996: Version 0.5
  22.              setftime and getftime implemented
  23.              some optimizations done (integer -> longint)
  24.              procedure fsearch from the LINUX version ported
  25.              msdos call implemented
  26.   26th november 1996:
  27.              better fexpand
  28.   29th january 1997:
  29.              bug in getftime and setftime removed
  30.              setfattr and getfattr added
  31.    2th february 1997: Version 0.9
  32.              bug of searchrec corrected
  33. }
  34.  
  35. unit dos;
  36.  
  37.   interface
  38.  
  39.     uses
  40.        strings;
  41.  
  42.     const
  43.        { bit masks for CPU flags}
  44.        fcarry = $0001;
  45.        fparity = $0004;
  46.        fauxiliary = $0010;
  47.        fzero = $0040;
  48.        fsign = $0080;
  49.        foverflow  = $0800;
  50.  
  51.        { Bitmasken fuer Dateiattribute }
  52.        readonly = $01;
  53.        hidden = $02;
  54.        sysfile = $04;
  55.        volumeid = $08;
  56.        directory = $10;
  57.        archive = $20;
  58.        anyfile = $3F;
  59.        fmclosed = $D7B0;
  60.        fminput = $D7B1;
  61.        fmoutput = $D7B2;
  62.        fminout = $D7B3;
  63.  
  64.     type
  65.        { some string types }
  66.        comstr = string[127];        { Kommandozeilenstring }
  67.        pathstr = string[79];        { String fuer einen Pfadnamen }
  68.        dirstr = string[67];         { String fuer kompletten Pfad }
  69.        namestr = string[8];         { Dateinamenstring }
  70.        extstr = string[4];          { String fuer Dateinamensuffix }
  71.  
  72.        { search record which is used by findfirst and findnext }
  73. {$PACKRECORDS 1}
  74.        searchrec = record
  75.           fill : array[1..21] of byte;
  76.           attr : byte;
  77.           time : longint;
  78.           reserved : word; { requires the DOS extender (DJ GNU-C) }
  79.           size : longint;
  80.           name : string[15]; { the same size as declared by (DJ GNU C) }
  81.        end;
  82. {$PACKRECORDS 2}
  83.  
  84.        { file record for untyped files }
  85.        filerec = record
  86.           handle : word;
  87.           mode : word;
  88.           recsize : word;
  89.           _private : array[1..26] of byte;
  90.           userdata: array[1..16] of byte;
  91.           name: array[0..79] of char;
  92.        end;
  93.  
  94.        { file record for text files }
  95.        textbuf = array[0..127] of char;
  96.  
  97.        textrec = record
  98.           handle : word;
  99.           mode : word;
  100.           bufSize : word;
  101.           _private : word;
  102.           bufpos : word;
  103.           bufend : word;
  104.           bufptr : ^textbuf;
  105.           openfunc : pointer;
  106.           inoutfunc : pointer;
  107.           flushfunc : pointer;
  108.           closefunc : pointer;
  109.           userdata : array[1..16] of byte;
  110.           name : array[0..79] of char;
  111.           buffer : textbuf;
  112.        end;
  113.  
  114.        { data structure for the registers needed by msdos and intr }    
  115.        registers = record
  116.          case i : integer of
  117.             0 : (ax,f1,bx,f2,cx,f3,dx,f4,bp,f5,si,f51,di,f6,ds,f7,es,f8,flags,fs,gs : word);
  118.             1 : (al,ah,f9,f10,bl,bh,f11,f12,cl,ch,f13,f14,dl,dh : byte);
  119.             2 : (eax,  ebx,  ecx,  edx,  ebp,  esi,  edi : longint);
  120.        end;
  121.  
  122.        { record for date and time } 
  123.        datetime = record
  124.           year,month,day,hour,min,sec : word;
  125.        end;
  126.  
  127.     var
  128.        { error variable }
  129.        doserror : integer;
  130.  
  131.     procedure getdate(var year,month,day,dayofweek : word);
  132.     procedure gettime(var hour,minute,second,sec100 : word);
  133.     function dosversion : word;
  134.     procedure setdate(year,month,day : word);
  135.     procedure settime(hour,minute,second,sec100 : word);
  136.     procedure getcbreak(var breakvalue : boolean);
  137.     procedure setcbreak(breakvalue : boolean);
  138.     procedure getverify(var verify : boolean);
  139.     procedure setverify(verify : boolean);
  140.     function diskfree(drive : byte) : longint;
  141.     function disksize(drive : byte) : longint;
  142.     procedure findfirst(const path : pathstr;attr : word;var f : searchRec);
  143.     procedure findnext(var f : searchRec);
  144.  
  145.     { is a dummy }
  146.     procedure swapvectors;
  147.  
  148. {   not supported:
  149.     procedure getintvec(intno : byte;var vector : pointer);
  150.     procedure setintvec(intno : byte;vector : pointer);
  151.     procedure keep(exitcode : word);
  152. }
  153.     procedure msdos(var regs : registers); 
  154.     procedure intr(intno : byte;var regs : registers);
  155.  
  156.     procedure getfattr(var f;var attr : word);
  157.     procedure setfattr(var f;attr : word);
  158.  
  159.     function fsearch(const path : pathstr;dirlist : string) : pathstr;
  160.     procedure getftime(var f;var time : longint);
  161.     procedure setftime(var f;time : longint);
  162.     procedure packtime (var d: datetime; var time: longint);
  163.     procedure unpacktime (time: longint; var d: datetime);
  164.     function fexpand(const path : pathstr) : pathstr;
  165.     procedure fsplit(path : pathstr;var dir : dirstr;var name : namestr;
  166.       var ext : extstr);
  167.     procedure exec(const path : pathstr;const comline : comstr);
  168.     function dosexitcode : word;
  169.     function envcount : longint;
  170.     function envstr(index : longint) : string;
  171.     function getenv(const envvar : string): string;
  172.  
  173.   implementation
  174.  
  175.     { this was first written for the LINUX version,    }
  176.     { by Michael Van Canneyt but it works also         }
  177.     { for the DOS version (I hope so)                  }
  178.     function fsearch(const path : pathstr;dirlist : string) : pathstr;
  179.  
  180.       var
  181.          newdir : pathstr;
  182.          p1 : byte;
  183.          s : searchrec;
  184.  
  185.       begin
  186.          if (pos('?',path)<>0) or (pos('*',path)<>0) then
  187.            { No wildcards allowed in these things }
  188.            fsearch:='' 
  189.          else
  190.            begin
  191.               repeat
  192.                 { get first path }
  193.                 p1:=pos(';',dirlist);
  194.                 if p1>0 then
  195.                   begin
  196.                      newdir:=copy(dirlist,1,p1-1);
  197.                      delete(dirlist,1,p1)
  198.                   end
  199.                 else
  200.                   begin
  201.                      newdir:=dirlist;
  202.                      dirlist:=''
  203.                   end;
  204.                 findfirst(newdir+'\'+path,anyfile,s);
  205.                 if doserror=0 then
  206.                   begin
  207.                      newdir:=newdir+'\'+s.name;
  208.                      { this was for LINUX:
  209.                      if pos('.\',newdir)=1 then
  210.                        delete(newdir, 1, 2)
  211.                      { DOS strips off an initial .\ }
  212.                      }
  213.                   end
  214.                 else newdir:='';
  215.               until(dirlist='') or (length(newdir)>0);
  216.               fsearch:=newdir;
  217.            end;
  218.       end;
  219.  
  220.     procedure getftime(var f;var time : longint);
  221.  
  222.       begin
  223.          asm
  224.             { load handle } 
  225.             movl f,%ebx
  226.             movw (%ebx),%bx
  227.             { get date }
  228.             movw $0x5700,%ax
  229.             int $0x21
  230.             shll $16,%edx
  231.             movw %cx,%dx
  232.             movl time,%ebx
  233.             movl %edx,(%ebx)
  234.             xorb %ah,%ah
  235.             movw %ax,U_DOS_DOSERROR
  236.          end;
  237.       end;
  238.  
  239.    procedure setftime(var f;time : longint);
  240.  
  241.       begin
  242.          asm
  243.             { load handle } 
  244.             movl f,%ebx
  245.             movw (%ebx),%bx
  246.             movl time,%edx
  247.             movl %edx,%ecx
  248.             shrl $16,%edx
  249.             { set date }
  250.             movw $0x5701,%ax
  251.             int $0x21
  252.             xorb %ah,%ah
  253.             movw %ax,U_DOS_DOSERROR
  254.          end;
  255.       end;
  256.  
  257.     procedure msdos(var regs : registers);
  258.  
  259.       begin
  260.          intr($21,regs);
  261.       end;
  262.  
  263.     procedure intr(intno : byte;var regs : registers);
  264.  
  265.       begin
  266.          asm
  267.             .data
  268.     int86:
  269.             .byte        0xcd
  270.     int86_vec:
  271.             .byte        0x03
  272.             jmp        int86_retjmp
  273.  
  274.             .text
  275.             movl        8(%ebp),%eax
  276.             movb        %al,int86_vec
  277.  
  278.             movl        10(%ebp),%eax
  279.             // do not use first int
  280.             addl        $2,%eax
  281.  
  282.             movl        4(%eax),%ebx
  283.             movl        8(%eax),%ecx
  284.             movl        12(%eax),%edx
  285.             movl        16(%eax),%ebp
  286.             movl        20(%eax),%esi
  287.             movl        24(%eax),%edi
  288.             movl        (%eax),%eax
  289.  
  290.             jmp        int86
  291.     int86_retjmp:
  292.             pushf
  293.             pushl    %ebp
  294.             pushl       %eax
  295.             movl        %esp,%ebp
  296.             // calc EBP new
  297.             addl        $12,%ebp
  298.             movl        10(%ebp),%eax
  299.             // do not use first int
  300.             addl        $2,%eax
  301.  
  302.             popl        (%eax)
  303.             movl        %ebx,4(%eax)
  304.             movl        %ecx,8(%eax)
  305.             movl        %edx,12(%eax)
  306.             // restore EBP
  307.             popl    %edx
  308.             movl    %edx,16(%eax)
  309.             movl        %esi,20(%eax)
  310.             movl        %edi,24(%eax)
  311.             // ignore ES and DS
  312.             popl        %ebx        /* flags */
  313.             movl        %ebx,32(%eax)
  314.             // FS and GS too
  315.          end;
  316.       end;
  317.  
  318.     var
  319.        lastdosexitcode : word;
  320.  
  321.     procedure exec(const path : pathstr;const comline : comstr);
  322.  
  323.       procedure do_system(p : pchar);
  324.  
  325.         begin
  326.            asm
  327.               movl 12(%ebp),%ebx
  328.               movw $0xff07,%ax
  329.               int $0x21
  330.               movw %ax,_LASTDOSEXITCODE
  331.            end;
  332.         end;
  333.  
  334.       var
  335.          execute : string;
  336.          b : array[0..255] of char;
  337.  
  338.       begin
  339.          execute:=path+' '+comline;
  340.          move(execute[1],b,length(execute));
  341.          b[length(execute)]:=#0;
  342.          do_system(b);
  343.       end;
  344.  
  345.     function dosexitcode : word;
  346.  
  347.       begin
  348.          dosexitcode:=lastdosexitcode;
  349.       end;
  350.  
  351.     function dosversion : word;
  352.  
  353.       begin
  354.          asm
  355.             movb $0x30,%ah
  356.             pushl %ebp
  357.             int $0x21
  358.             popl %ebp
  359.             leave
  360.             ret
  361.          end;
  362.       end;
  363.  
  364.     procedure getdate(var year,month,day,dayofweek : word);
  365.  
  366.       begin
  367.          asm
  368.             movb $0x2a,%ah
  369.             pushl %ebp
  370.             int $0x21
  371.             popl %ebp
  372.             xorb %ah,%ah
  373.             movl 20(%ebp),%edi
  374.             stosw
  375.             movl 16(%ebp),%edi
  376.             movb %dl,%al
  377.             stosw
  378.             movl 12(%ebp),%edi
  379.             movb %dh,%al
  380.             stosw
  381.             movl 8(%ebp),%edi
  382.             movw %cx,%ax
  383.             stosw
  384.          end;
  385.       end;
  386.  
  387.     procedure setdate(year,month,day : word);
  388.  
  389.       begin
  390.          asm
  391.             movw 8(%ebp),%cx
  392.             movb 10(%ebp),%dh
  393.             movb 12(%ebp),%dl
  394.             movb $0x2b,%ah
  395.             pushl %ebp
  396.             int $0x21
  397.             popl %ebp
  398.             xorb %ah,%ah
  399.             movw %ax,U_DOS_DOSERROR
  400.          end;
  401.       end;
  402.  
  403.     procedure gettime(var hour,minute,second,sec100 : word);
  404.  
  405.       begin
  406.          asm
  407.             movb $0x2c,%ah
  408.             pushl %ebp
  409.             int $0x21
  410.             popl %ebp
  411.             xorb %ah,%ah
  412.             movl 20(%ebp),%edi
  413.             movb %dl,%al
  414.             stosw
  415.             movl 16(%ebp),%edi
  416.             movb %dh,%al
  417.             stosw
  418.             movl 12(%ebp),%edi
  419.             movb %cl,%al
  420.             stosw
  421.             movl 8(%ebp),%edi
  422.             movb %ch,%al
  423.             stosw
  424.          end;
  425.       end;
  426.  
  427.     procedure settime(hour,minute,second,sec100 : word);
  428.  
  429.       begin
  430.          asm
  431.             movb 8(%ebp),%ch
  432.             movb 10(%ebp),%cl
  433.             movb 12(%ebp),%dh
  434.             movb 14(%ebp),%dl
  435.             movb $0x2d,%ah
  436.             pushl %ebp
  437.             int $0x21
  438.             popl %ebp
  439.             xorb %ah,%ah
  440.             movw %ax,U_DOS_DOSERROR
  441.          end;
  442.       end;
  443.  
  444.     procedure getcbreak(var breakvalue : boolean);
  445.  
  446.       begin
  447.          asm
  448.             movw $0x3300,%ax
  449.             pushl %ebp
  450.             int $0x21
  451.             popl %ebp
  452.             movl 8(%ebp),%eax
  453.             movb %dl,(%eax)
  454.          end;
  455.       end;
  456.  
  457.     procedure setcbreak(breakvalue : boolean);
  458.  
  459.       begin
  460.          asm
  461.             movb 8(%ebp),%dl
  462.             movl $0x3301,%ax
  463.             pushl %ebp
  464.             int $0x21
  465.             popl %ebp
  466.          end;
  467.       end;
  468.  
  469.     procedure getverify(var verify : boolean);
  470.  
  471.       begin
  472.          asm
  473.             movb $0x54,%ah
  474.             pushl %ebp
  475.             int $0x21
  476.             popl %ebp
  477.             movl 8(%ebp),%edi
  478.             stosb
  479.          end;
  480.       end;
  481.  
  482.     procedure setverify(verify : boolean);
  483.  
  484.       begin
  485.          asm
  486.             movb 8(%ebp),%al
  487.             movl $0x2e,%ah
  488.             pushl %ebp
  489.             int $0x21
  490.             popl %ebp
  491.          end;
  492.       end;
  493.  
  494.     function diskfree(drive : byte) : longint;
  495.  
  496.       begin
  497.          asm
  498.             movb 8(%ebp),%dl
  499.             movb $0x36,%ah
  500.             pushl %ebp
  501.             int $0x21
  502.             popl %ebp
  503.             cmpw $-1,%ax
  504.             je LDISKFREE1
  505.             mulw %cx
  506.             mulw %bx
  507.             shll $16,%edx
  508.             movw %ax,%dx
  509.             movl %edx,%eax
  510.             leave
  511.             ret
  512.          LDISKFREE1:
  513.             movl $-1,%eax
  514.             leave
  515.             ret
  516.          end;
  517.       end;
  518.  
  519.     function disksize(drive : byte) : longint;
  520.  
  521.       begin
  522.          asm
  523.             movb 8(%ebp),%dl
  524.             movb $0x36,%ah
  525.             pushl %ebp
  526.             int $0x21
  527.             popl %ebp
  528.             movw %dx,%bx
  529.             cmpw $-1,%ax
  530.             je LDISKSIZE1
  531.             mulw %cx
  532.             mulw %bx
  533.             shll $16,%edx
  534.             movw %ax,%dx
  535.             movl %edx,%eax
  536.             leave
  537.             ret
  538.          LDISKSIZE1:
  539.             movl $-1,%eax
  540.             leave
  541.             ret
  542.          end;
  543.       end;
  544.  
  545.     procedure searchrec2dossearchrec(var f : searchrec);
  546.  
  547.       var
  548.          l,i : longint;
  549.  
  550.       begin
  551.          l:=length(f.name);
  552.          for i:=1 to 12 do
  553.            f.name[i-1]:=f.name[i];
  554.          f.name[l]:=#0;
  555.       end;
  556.  
  557.     procedure dossearchrec2searchrec(var f : searchrec);
  558.  
  559.       var
  560.          l,i : longint;
  561.  
  562.       begin
  563.          for i:=0 to 12 do
  564.            if f.name[i]=#0 then
  565.              begin
  566.                 l:=i;
  567.                 break;
  568.              end;
  569.          for i:=11 downto 0 do
  570.            f.name[i+1]:=f.name[i];
  571.          f.name[0]:=chr(l);
  572.       end;
  573.  
  574.     procedure findfirst(const path : pathstr;attr : word;var f : searchRec);
  575.  
  576.       procedure _findfirst(path : pchar;attr : word;var f : searchrec);
  577.  
  578.         begin
  579.            asm
  580.               movl 18(%ebp),%edx
  581.               movb $0x1a,%ah
  582.               int $0x21
  583.               movl 12(%esp),%edx
  584.               movzwl 16(%esp),%ecx
  585.               movb $0x4e,%ah
  586.               int $0x21
  587.               jnc LFF
  588.               movw %ax,U_DOS_DOSERROR
  589.            LFF:
  590.            end;
  591.         end;
  592.  
  593.       var
  594.          path0 : array[0..80] of char;
  595.  
  596.       begin
  597.          { no error }
  598.          doserror:=0;
  599.          strpcopy(path0,path);
  600.          _findfirst(path0,attr,f);
  601.          dossearchrec2searchrec(f);
  602.       end;
  603.  
  604.     procedure findnext(var f : searchRec);
  605.  
  606.       procedure _findnext(var f : searchrec);
  607.  
  608.         begin
  609.            asm
  610.               movl 12(%ebp),%edx
  611.               movb $0x1a,%ah
  612.               int $0x21
  613.               movb $0x4f,%ah
  614.               int $0x21
  615.               jnc LFN
  616.               movw %ax,U_DOS_DOSERROR
  617.            LFN:
  618.            end;
  619.         end;
  620.  
  621.       begin
  622.          { no error }
  623.          doserror:=0;
  624.          searchrec2dossearchrec(f);
  625.          _findnext(f);
  626.          dossearchrec2searchrec(f);
  627.       end;
  628.  
  629.     procedure swapvectors;
  630.  
  631.       begin
  632.          { tut nichts, DOS-Extender übernimmt das Nötige }
  633.          { normalerweise selber                          }
  634.          { nur aus Kompatibilitätsgründen implementiert  }
  635.       end;
  636.  
  637.     type
  638.        ppchar = ^pchar;
  639.  
  640.     function envs : ppchar;
  641.  
  642.       begin
  643.          asm
  644.             movl _environ,%eax
  645.             leave
  646.             ret
  647.          end ['EAX'];
  648.       end;
  649.  
  650.     function envcount : longint;
  651.  
  652.       var
  653.          hp : ppchar;
  654.  
  655.       begin
  656.          hp:=envs;
  657.          envcount:=0;
  658.          while assigned(hp^) do
  659.            begin
  660.               { not the best solution, but quite understandable }
  661.               inc(envcount);
  662.               hp:=hp+4;
  663.            end;
  664.       end;
  665.  
  666.     function envstr(index : longint) : string;
  667.  
  668.       var
  669.          hp : ppchar;
  670.  
  671.       begin
  672.          if (index<=0) or (index>envcount) then
  673.            begin
  674.               envstr:='';
  675.               exit;
  676.            end;
  677.          hp:=envs+4*(index-1);
  678.          envstr:=strpas(hp^);
  679.       end;
  680.  
  681.     function getenv(const envvar : string) : string;
  682.  
  683.       var
  684.          hs,_envvar : string;
  685.          eqpos,i : longint;
  686.  
  687.       begin
  688.          _envvar:=upcase(envvar);
  689.          getenv:='';
  690.          for i:=1 to envcount do
  691.            begin
  692.               hs:=envstr(i);
  693.               eqpos:=pos('=',hs);
  694.               if copy(hs,1,eqpos-1)=_envvar then
  695.                 begin
  696.                    getenv:=copy(hs,eqpos+1,length(hs)-eqpos);
  697.                    exit;
  698.                 end;
  699.            end;
  700.       end;
  701.  
  702.     procedure fsplit(path : pathstr;var dir : dirstr;var name : namestr;
  703.       var ext : extstr);
  704.  
  705.       var
  706.          p1 : byte;
  707.  
  708.       begin
  709.          { try to find out a extension }
  710.          p1:=pos('.',path);
  711.          if p1>0 then
  712.            begin
  713.               ext:=copy(path,p1,4);
  714.               delete(path,p1,length(path)-p1+1);
  715.            end
  716.          else
  717.            ext:='';
  718.          { get drive name }
  719.          p1:=pos(':',path);
  720.          if p1>0 then
  721.            begin
  722.               dir:=path[1]+':';
  723.               delete(path,1,p1);
  724.            end
  725.          else
  726.            dir:='';
  727.          { split the path and the name, there are no more path informtions }
  728.          { if path contains no backslashes                                 }
  729.          while true do
  730.            begin
  731.               p1:=pos('\',path);
  732.               if p1=0 then
  733.                 break;
  734.               dir:=dir+copy(path,1,p1);
  735.               delete(path,1,p1);
  736.            end;
  737.          name:=path;
  738.       end;
  739.  
  740.     function fexpand(const path : pathstr) : pathstr;
  741.  
  742.       function get_current_drive : byte;
  743.       
  744.         var
  745.            r : registers;
  746.            
  747.         begin
  748.            r.ah:=$19;
  749.            msdos(r);
  750.            get_current_drive:=r.al;
  751.         end;           
  752.  
  753.        var
  754.           s,pa : string[79];
  755.  
  756.        begin
  757.           { There are differences between FPKPascal and Turbo Pascal
  758.             e.g. for the string 'D:\DEMO\..\HELLO' which isn't handled }
  759.           getdir(0,s);
  760.           pa:=upcase(path);
  761.           if (ord(pa[0])>1) and (((pa[1]>='A') and (pa[1]<='Z')) and (pa[2]=':')) then
  762.             begin
  763.                if (ord(pa[0])>2) and (pa[3]<>'\') then
  764.                  if pa[1]=s[1] then
  765.                    pa:=s+'\'+copy (pa,3,length(pa))
  766.                  else
  767.                    pa:=pa[1]+':\'+copy (pa,3,length(pa))
  768.             end
  769.           else
  770.             if pa[1]='\' then 
  771.               pa:=s[1]+':'+pa
  772.             else if s[0]=#3 then
  773.               pa:=s+pa
  774.             else
  775.               pa:=s+'\'+pa;
  776.           fexpand:=pa;
  777.        end;
  778.  
  779.      procedure packtime(var d : datetime;var time : longint);
  780.  
  781.        var
  782.           zs : longint;
  783.  
  784.        begin
  785.           time:=-1980;
  786.           time:=time+d.year and 127;
  787.           time:=time shl 4;
  788.           time:=time+d.month;
  789.           time:=time shl 5;
  790.           time:=time+d.day;
  791.           time:=time shl 16;
  792.           zs:=d.hour;
  793.           zs:=zs shl 6;
  794.           zs:=zs+d.min;
  795.           zs:=zs shl 5;
  796.           zs:=zs+d.sec div 2;
  797.           time:=time+(zs and $ffff);
  798.        end;
  799.  
  800.      procedure unpacktime (time: longint; var d: datetime);
  801.  
  802.        begin
  803.           d.sec:=(time and 31) * 2;
  804.           time:=time shr 5;
  805.           d.min:=time and 63;
  806.           time:=time shr 6;
  807.           d.hour:=time and 31;
  808.           time:=time shr 5;
  809.           d.day:=time and 31;
  810.           time:=time shr 5;
  811.           d.month:=time and 15;
  812.           time:=time shr 4;
  813.           d.year:=time + 1980;
  814.        end;
  815.  
  816.     procedure getfattr(var f;var attr : word);
  817.  
  818.       var
  819.          { to avoid problems }
  820.          n : array[0..255] of char; 
  821.          r : registers;
  822.  
  823.       begin            
  824.          strpcopy(n,filerec(f).name);
  825.          r.ax:=$4300;
  826.          r.edx:=longint(@n);
  827.          msdos(r);
  828.          attr:=r.cx;
  829.       end;
  830.  
  831.     procedure setfattr(var f;attr : word);
  832.  
  833.       var
  834.          { to avoid problems }
  835.          n : array[0..255] of char; 
  836.          r : registers;
  837.  
  838.       begin
  839.          strpcopy(n,filerec(f).name);
  840.          r.ax:=$4301;
  841.          r.edx:=longint(@n);
  842.          r.cx:=attr;
  843.          msdos(r);
  844.       end;
  845.  
  846. end.
  847.